<?php

namespace Cframe;

class Url
{
    private $config = array();
    private $method = array();

    public function __construct()
    {
        $this->loadRoute();
    }

    public function loadUrl($url)
    {
        return $this->formatUrl($url);
    }

    private function loadRoute()
    {
        if (empty($this->config)) {
            $this->config = include ROUTE_PATH . "route.php";
            $config = include CON_PATH . 'route.php';
            if (is_array($config) && !empty($config)) {
                $this->config = array_merge($this->config, $config);
            }
        }
    }

    public function registerRoute(array $userR)
    {
        if (!empty($userR)) {
            $this->config = array_merge($this->config, $userR);
        }
    }

    public function Build($controller = '',$is_rewite = false){
        $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
        $domain = empty($domain) ? $http_type . $_SERVER['HTTP_HOST'] : $http_type . $domain;
        if ($is_rewite){
            $controller = 'index.php/'.$controller;
        }
        return $this->reUrl($domain . ROOT_URL . "/" . $controller);
    }

    public function CreateUrl($controller = '',array $parm = array() , $domain = '',  $is_rewrite = false)
    {
        $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
        $domain = empty($domain) ? $http_type . $_SERVER['HTTP_HOST'] : $http_type . $domain;
        $parm2 = '/';
        foreach ($parm as $k => $v){
            $parm2 .= "{$k}/{$v}/";
        }
        if (empty($controller)) {

            if (!$is_rewrite) {
                return $this->reUrl($domain . ROOT_URL . 'index.php' . $parm2);
            }
            return $this->reUrl($domain . ROOT_URL . $parm2);
        } else {
            $this->reRoute($controller);
            if (!$is_rewrite) {
                return $this->reUrl($domain . ROOT_URL . 'index.php/' . $controller . $parm2);
            }
            return $this->reUrl($domain . ROOT_URL . "/" . $controller . $parm2) ;
        }
    }

    private function reUrl($url){
        return preg_replace('/([^:])[\/\\\\]{2,}/','$1/',$url);
    }

    private function formatUrl($url)
    {
        $url = str_replace(ROOT_URL, '', $url);
        $urlArray = explode('/', $url);
        if (empty($urlArray[0])) {
            array_shift($urlArray);
        }
        $this->findRoute($urlArray);
        $this->getClass($urlArray);
        return $urlArray;
    }

    private function getClass(&$array)
    {
        $temp = '';
        if (!is_callable($array[0])) {
            if (strpos($array[0], '\\') === false) {
                $temp = "\\";
                $temp1 = array_splice($array,0,2);;
                array_unshift($temp1,CON_NAME);
                array_splice($temp1,2,0,APP_NAME);
                $temp .= implode('\\',$temp1);
            } else {
                $array = explode("@", $array[0]);
                $temp = array_shift($array);
            }
        }
        $function = array_shift($array);
        $array['class'] = $temp;
        $array['func'] = $function;
        for ($i = 0; $i < count($array); $i += 2) {
            if (!isset($array[$i])) {
                break;
            }if (empty($array[$i])){
                break;
            }
            $key = $array[$i];
            $val = isset($array[$i + 1]) ? $array[$i + 1] : '';
            $_REQUEST[$key] = $val;
        }
        $array['method'] = $this->method;
    }

    private function findRoute(&$val)
    {
        if (!isset($val[0])) {
            return false;
        }
        $vals = $val[0];
        $one_test = '';
        $keys = array_keys($this->config);
        foreach ($keys as $k) {
            if ($k == $vals || strpos($k, $vals . '/') !== false) {
                $one_test = $k;
            }
        }
        unset($keys);
        if (!empty($one_test)) {
            if (!is_array($this->config[$one_test])) {
                $this->config[$one_test] = [["get", "post"], $this->config[$one_test], []];
            }
            $value = ($this->config[$one_test]);
            $count = explode('/', $one_test);
            if (count($count) > 1) {
                array_shift($count);
                if (empty($value[2])) {
                    array_walk($count, function ($value1) use (&$value) {
                        $name = str_replace([':', '[', ']'], ['', '', ''], $value1);
                        $value[2][$name] = ".*";
                    });
                }
                $i = 1;
                foreach ($value[2] as $key => $vals) {
                    $vals = "#^({$vals})$#";
                    $values = isset($val[$i])?$val[$i]:'';
                    if (preg_match($vals, $values)) {
                        $_REQUEST[$key] = $values;
                        unset($val[$i]);
                    } else {
                        if (strpos($count[$i], '[:') === false) {
                            throw new \Exception("Url Error parameter `{$key}` Not Found");
                        }
                    }
                    $i ++;
                }
                unset($count);
            }
            if (!is_callable($value[1])){
                $data = explode("/", $value[1]);
                $this->method = $value[0];
                array_shift($val);
                $val = array_merge($data, $val);
            }else{
                $data = $value[1];
                $this->method = $value[0];
                array_shift($val);
                $val[] = $data;
            }
        }
    }

    private function reRoute(&$val)
    {
        foreach ($this->config as $k => $value) {
            if (!is_array($value)) {
                $value = [["get", "post"], $value, []];
            }
            if ($value[1] == $val || strpos($val, $value[1] . '/') !== false) {
                $val = $k;
                break;
            }
        }
    }
}